package net.qiqb.core.optional.persistence;

import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import net.qiqb.core.domain.annotation.AggregatePersistence;
import net.qiqb.core.domain.annotation.BaseEntity;
import net.qiqb.core.executing.ExecutingContext;
import net.qiqb.core.executing.ExecutingContextHolder;

/**
 * 抽象的领域持久化对象
 *
 * @param <AR>
 */
@Slf4j
public abstract class AbstractAggregatePersistence<AR> implements AggregatePersistence<AR> {

    @Override
    public void persistAggregate(AR newAR, AR oldAR) {
        if (isDelete(newAR)) {
            try {
                doRemove(newAR, oldAR);
            } finally {
                ExecutingContextHolder.current().removeAttribute(ExecutingContext.DELETE_AGGREGATE_ROOT_OBJ);
            }
            return;
        }
        if (isNew(newAR)) {
            try {
                doAdd(newAR);
            } finally {
                ExecutingContextHolder.current().removeAttribute(ExecutingContext.NEW_AGGREGATE_ROOT_OBJ);
            }
            return;
        }
        // 更新
        doModify(newAR, oldAR);
    }

    protected boolean isDelete(AR ar) {
        return ar.equals(ExecutingContextHolder.current().getAttribute(ExecutingContext.DELETE_AGGREGATE_ROOT_OBJ));
    }

    protected boolean isNew(AR ar) {
        return ExecutingContextHolder.current().isNewEntityId(getId(ar));
    }


    protected Object getId(AR aggregateRoot) {
        // 获取领域对象的id
        final Object id = lookupAggregateRootId(aggregateRoot);
        if (id != null) {
            return id;
        }
        log.error("找不到聚合根ID:{}", aggregateRoot.getClass());
        throw new IllegalStateException("找不到聚合根ID");
    }

    private Object lookupAggregateRootId(Object aggregateRootObj) {
        if (aggregateRootObj instanceof BaseEntity<?>) {
            return ((BaseEntity<?>) aggregateRootObj).getId();
        }
        // 默认找id 属性
        final Object idValue = ReflectUtil.getFieldValue(aggregateRootObj, "id");
        if (idValue != null) {
            return idValue;
        }
        throw new RuntimeException("找不到聚合根id");
    }

    /**
     * 执行聚合根新增操作
     *
     * @param newAR 待新增的领域聚合根对象
     */
    protected abstract void doAdd(AR newAR);

    /**
     * 根据聚合根执行领域对象更新操作
     *
     * @param newAR 待更新的领域聚合根对象
     * @param oldAR 未执行业务逻辑的聚合对象
     */
    protected abstract void doModify(AR newAR, AR oldAR);

    /**
     * 根据聚合根执行领域对象删除操作
     *
     * @param newAR 待删除的领域聚合根对象
     * @param oldAR 未执行业务逻辑的聚合对象
     */
    protected abstract void doRemove(AR newAR, AR oldAR);


}
